﻿namespace TestTool.GUI.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Net.Sockets;
    using System.Runtime.CompilerServices;
    using System.ServiceModel;
    using TestTool.GUI.Data;
    using TestTool.GUI.Enums;
    using TestTool.GUI.Utils;
    using TestTool.GUI.Views;
    using TestTool.Proxies.WSDiscovery;
    using TestTool.Tests.Common.Discovery;
    using TestTool.Tests.Definitions.Data;

    internal class DiscoveryController : Controller<IDiscoveryView>
    {
        private ManagementServiceProvider _client;
        private int _queriesRunning;
        private bool _requestPending;

        public event Action<DeviceDiscoveryData> DeviceDiscovered;

        public event TestTool.GUI.Utils.ManagementServiceProvider.DeviceInformationReceived DeviceInformationReceived;

        public event Action DiscoveryCompleted;

        public event Action<Exception> DiscoveryError;

        public event Action DiscoveryStarted;

        public DiscoveryController(IDiscoveryView view) : base(view)
        {
        }

        public void GetDeviceInformation(string address)
        {
            this.UpdateCredentials();
            this._requestPending = true;
            this.InitializeClient(address);
            this._client.GetDeviceInformationEx();
        }

        public List<NetworkInterfaceDescription> GetNetworkInterfaces()
        {
            return DiscoveryHelper.GetNetworkInterfaces();
        }

        private void InitializeClient(string address)
        {
            DeviceEnvironment deviceEnvironment = ContextController.GetDeviceEnvironment();
            this._client = new ManagementServiceProvider(address, deviceEnvironment.Timeouts.Message);
            this._client.ExceptionThrown += new Action<string, Exception>(this.OnExceptionThrown);
            this._client.FaultThrown += new Action<string, FaultException>(this.OnFaultThrown);
            this._client.OnDeviceInformationReceived += this.DeviceInformationReceived;
            this._client.OperationCompleted += new Action(this.ReportOperationCompleted);
            this._client.OperationStarted += new Action(this.ReportOperationStarted);
            this._client.Timeout = deviceEnvironment.Timeouts.Message;
        }

        public override void LoadSavedContext(SavedContext context)
        {
            if (context.DiscoveryContext != null)
            {
                IPAddress address;
                if (IPAddress.TryParse(context.DiscoveryContext.DeviceAddress, out address))
                {
                    base.View.DeviceAddress = address;
                }
                base.View.ServiceAddress = context.DiscoveryContext.ServiceAddress;
                base.View.NICAddress = context.DiscoveryContext.InterfaceAddress;
                base.View.ShowOptions = context.DiscoveryContext.ShowSearchOptions;
                base.View.SearchScopes = context.DiscoveryContext.SearchScopes;
            }
            if ((context.DeviceEnvironment != null) && (context.DeviceEnvironment.Credentials != null))
            {
                base.View.UserName = context.DeviceEnvironment.Credentials.UserName;
                base.View.Password = context.DeviceEnvironment.Credentials.Password;
            }
            this.UpdateContext();
            base.View.SwitchToState(TestTool.GUI.Enums.ApplicationState.Idle);
        }

        protected void OnDeviceDiscovered(object sender, DiscoveryMessageEventArgs e, List<DeviceDiscoveryData> allDevices, List<DiscoveryErrorEventArgs> errors, DiscoveryUtils.DiscoveryType[][] types)
        {
            if (this.DeviceDiscovered != null)
            {
                List<DeviceDiscoveryData> collection = DiscoveryUtils.GetDevices(e.Message.ToSoapMessage<ProbeMatchesType>(), e.Sender, types);
                allDevices.AddRange(collection);
                foreach (DeviceDiscoveryData data in collection)
                {
                    this.DeviceDiscovered(data);
                }
            }
        }

        protected void OnDiscoveryError(object sender, DiscoveryErrorEventArgs e, List<DiscoveryErrorEventArgs> errors)
        {
            if (errors != null)
            {
                errors.Add(e);
            }
            else if (this.DiscoveryError != null)
            {
                this.DiscoveryError(e.Exception);
            }
        }

        protected void OnDiscoveryFinished(object sender, EventArgs e, List<DeviceDiscoveryData> allDevices, List<DiscoveryErrorEventArgs> errors)
        {
            this._queriesRunning--;
            if (this._queriesRunning == 0)
            {
                if (errors.Count > 0)
                {
                    if (this.DiscoveryError != null)
                    {
                        this.DiscoveryError(errors[0].Exception);
                    }
                }
                else if ((allDevices.Count == 0) && (this.DiscoveryError != null))
                {
                    Exception exception = new Exception(string.Format("Device did not respond or device type is not {0} ", "NetworkVideoTransmitter"));
                    this.DiscoveryError(exception);
                }
                if (this.DiscoveryCompleted != null)
                {
                    this.DiscoveryCompleted();
                }
            }
        }

        private void OnExceptionThrown(string stage, Exception exc)
        {
            base.View.ShowError(exc);
            this._requestPending = false;
            base.ReportOperationCompleted();
        }

        private void OnFaultThrown(string stage, FaultException exc)
        {
            base.View.ShowError(exc);
            this._requestPending = false;
            base.ReportOperationCompleted();
        }

        public void ProbeDevice(IPAddress address)
        {
            IPAddress local = (address.AddressFamily == AddressFamily.InterNetworkV6) ? IPAddress.IPv6Any : IPAddress.Any;
            this.ProbeInternal(local, address);
        }

        public void ProbeDevice(IPAddress local, IPAddress remote)
        {
            this.ProbeInternal(local, remote);
        }

        protected void ProbeInternal(IPAddress local, IPAddress remote)
        {
            List<DiscoveryErrorEventArgs> errors = new List<DiscoveryErrorEventArgs>();
            List<DeviceDiscoveryData> devices = new List<DeviceDiscoveryData>();
            DiscoveryUtils.DiscoveryType[][] types = new DiscoveryUtils.DiscoveryType[][] { DiscoveryUtils.GetOnvif10Type(), DiscoveryUtils.GetOnvif20Type() };
            TestTool.Tests.Common.Discovery.Discovery discovery = new TestTool.Tests.Common.Discovery.Discovery(local);
            discovery.Discovered += (s, e) => this.OnDeviceDiscovered(s, e, devices, errors, types);
            discovery.DiscoveryFinished += (s, e) => this.OnDiscoveryFinished(s, e, devices, errors);
            discovery.ReceiveError += (s, e) => this.OnDiscoveryError(s, e, errors);
            string[] scopes = null;
            string searchScopes = base.View.SearchScopes;
            if (!string.IsNullOrEmpty(searchScopes))
            {
                scopes = searchScopes.Replace(Environment.NewLine, " ").Split(new char[] { ' ' });
                List<string> list = new List<string>();
                foreach (string str2 in scopes)
                {
                    if (!string.IsNullOrEmpty(str2))
                    {
                        list.Add(str2);
                    }
                }
                scopes = list.ToArray();
            }
            this._queriesRunning = 1;
            if (remote != IPAddress.None)
            {
                discovery.Probe(remote, types, scopes);
            }
            else
            {
                discovery.Probe(types, scopes);
            }
            if (this.DiscoveryStarted != null)
            {
                this.DiscoveryStarted();
            }
        }

        public void RunDiscovery(IPAddress networkInterface)
        {
            this.ProbeInternal(networkInterface, IPAddress.None);
        }

        public override void Stop()
        {
            if (this._requestPending)
            {
                this._client.Stop();
            }
        }

        public override void UpdateContext()
        {
            DiscoveredDevices devices = new DiscoveredDevices {
                NIC = base.View.NIC,
                Current = new DeviceInfoFull()
            };
            devices.Current.ByDiscovery = base.View.Current;
            devices.ServiceAddress = base.View.ServiceAddress;
            devices.DeviceAddress = base.View.DeviceAddress;
            devices.SearchScopes = base.View.SearchScopes;
            devices.ShowSearchOptions = base.View.ShowOptions;
            foreach (DeviceDiscoveryData data in base.View.Devices)
            {
                DeviceInfoFull item = new DeviceInfoFull {
                    ByDiscovery = data
                };
                devices.Discovered.Add(item);
            }
            ContextController.UpdateDiscoveredDevices(devices);
            this.UpdateCredentials();
            base.View.UpdateFormTitle();
        }

        private void UpdateCredentials()
        {
            DeviceEnvironment deviceEnvironment = ContextController.GetDeviceEnvironment();
            deviceEnvironment.Credentials.Password = base.View.Password;
            deviceEnvironment.Credentials.UserName = base.View.UserName;
        }

        public override void UpdateView()
        {
            base.View.UpdateButtons();
        }

        public override bool RequestPending
        {
            get
            {
                return this._requestPending;
            }
        }
    }
}

